#pragma once

#include "state.h"
#include <assert.h>

#define PROPERTY_GET(type, name) type Get##name(void) { return m_p##name; }
#define PROPERTY_SET(type, name) void Set##name(type value) { m_p##name = value; }
#define PROPERTY_GET_SET(type, name) \
	PROPERTY_GET(type, name) \
	PROPERTY_SET(type, name)

template <class entity_type>
class StateMachine
{
private:
	entity_type* m_pOwner;

	State<entity_type>* m_pCurrentState;

	State<entity_type>* m_pPreviousState;

	State<entity_type>* m_pGlobalState;

public:
	StateMachine(entity_type* owner)
		: m_pOwner(owner)
		, m_pCurrentState(NULL)
		, m_pPreviousState(NULL)
		, m_pGlobalState(NULL)
	{}
	virtual ~StateMachine(void) {}

	PROPERTY_SET(State<entity_type>*, CurrentState)

	PROPERTY_SET(State<entity_type>*, GlobalState)

	void Update(void)
	{
		m_pCurrentState->Execute(m_pOwner);
		m_pGlobalState->Execute(m_pOwner);
	}

	void ChangeState(State<entity_type>* pNewState)
	{
		assert(m_pCurrentState && pNewState);

		m_pCurrentState->Exit(m_pOwner);

		m_pPreviousState = m_pCurrentState;

		m_pCurrentState = pNewState;

		m_pCurrentState->Enter(m_pOwner);
	}

	void RevertToPreviousState(void)
	{
		assert(m_pCurrentState && m_pPreviousState);

		m_pCurrentState->Exit(m_pOwner);

		m_pCurrentState = m_pPreviousState;

		m_pCurrentState->Enter(m_pOwner);
	}

};
